


# 为什么推荐只使用 db0
# ​​集群模式限制​​：Redis Cluster 只支持 db0，不支持多数据库
# ​​简化管理​​：单数据库简化了键空间管理和监控
# ​​性能考虑​​：多数据库切换需要额外开销
# ​​命名空间替代​​：可以使用键前缀（如 user:123）替代多数据库


# 一个字符串类型的智能存储最大容量是多少？  512M。

# 两种持久化机制 RDB 和 AOF 机制：
# RDB：定期将内存数据生成​​二进制快照​​（dump.rdb文件）
# AOF: 记录​​所有写操作命令​​（文本格式），追加到 appendonly.aof 文件



# 在分布式系统中，缓存和数据库同时存在时，如果有写操作的时候，「先操作数据库，再操作缓存」。如下：

# 1.读取缓存中是否有相关数据
# 2.如果缓存中有相关数据value，则返回
# 3.如果缓存中没有相关数据，则从数据库读取相关数据放入缓存中key->value，再返回
# 4.如果有更新写数据，则先操作数据库，再操作缓存
# 5.为了保证第四步更新缓存成功，使用binlog异步通知操作
# 6.如果是主从数据库，binglog取自于从库
# 7.如果是一主多从，每个从库都要采集binlog，然后消费端收到最后一台binlog数据才删除缓存




# 「缓存穿透」：指查询一个一定不存在的数据，由于缓存是不命中时需要从数据库查询，查不到数据则不写入缓存，这将导致这个不存在的数据每次请求都要到数据库去查询，进而给数据库带来压力。
# 如果是非法请求，我们在API入口，对参数进行校验，过滤非法值
# 果查询数据库为空，我们可以给缓存设置个空值，或者默认值。但是如有有写请求进来的话，需要更新缓存哈，以保证缓存一致性，同时，最后给缓存设置适当的过期时间。（业务上比较常用，简单有效）
# 使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时，先通过布隆过滤器判断值是否存在，存在才继续往下查

# 布隆过滤器原理： 空间效率极高， 查询速度极快  存在一定的误判率（查询存在不一定真存在）  不存在漏判（查询不存在，一定不存在）  不支持元素删除操作
#     将要添加的元素 e 分别通过 k 个哈希函数（h₁, h₂, ..., hₖ）进行计算。
#     得到 k 个位数组的索引位置
#     将位数组中这 k 个索引位置的值都设置为 1

# 如果所有位置的值都是 1：则布隆过滤器返回 "可能存在" (True)。
# 如果任何一个位置的值是 0：则布隆过滤器可以确定地返回 "肯定不存在" (False)。


# 「缓存雪奔：」 指缓存中数据大批量到过期时间，而查询数据量巨大，请求都直接访问数据库，引起数据库压力过大甚至down机。
# Redis 故障宕机也可能引起缓存雪奔。这就需要构造Redis高可用集群啦。
# 通过均匀设置过期时间解决，即让过期时间相对离散一点。如采用一个较大固定值+一个较小的随机值，5小时+0到1800秒酱紫。




# 「缓存击穿：」 指热点key在某个时间点过期的时候，而恰好在这个时间点对这个Key有大量的并发请求过来，从而大量的请求打到db。
#  互斥锁（分布式锁）​：原理​​：缓存失效时，仅允许一个线程查询数据库并更新缓存，其他线程阻塞等待
# 逻辑过期（异步更新）​：在缓存Value中存储​​逻辑过期时间​​（而非Redis TTL）。当数据"过期"时：立即返回旧数据；异步启动线程更新缓存
# 热点数据永不过期 + 异步刷新​： 对高频访问数据（如热搜榜）设置​​永久缓存​​，通过后台任务定时更新
# 缓存预热：系统启动或高峰前，主动加载热点数据到缓存

# ​​方案​​	​​      一致性​​	​       ​性能​​	​           ​实现复杂度​​	​       ​适用场景​​
# ​​互斥锁​​	   ✅ 强一致	    ⚠️ 中等	            ⭐⭐	        数据实时性要求高
# ​​逻辑过期​​	    ⚠️ 弱一致	   ✅ 高	        ⭐⭐⭐⭐	    允许短暂脏数据的高并发场景
# ​​热点永不过期​​	⚠️ 弱一致	   ✅ 高	            ⭐⭐	        低频更新的热点数据
# ​​缓存预热​​	    ✅ 强一致	  ✅ 高	        ⭐⭐⭐	        可预测的流量高峰（如大促）




# 缓存热key问题  ： 访问频率高的key，称为热点key。如果某一热点key的请求到服务器主机时，
# 由于请求量特别大，可能会导致主机资源不足，甚至宕机，从而影响正常的服务
# 识别 办法
# 凭经验判断哪些是热Key；
# 客户端统计上报；
# 服务代理层上报



# TTL: 用于获取指定键（key）的剩余生存时间（以秒为单位）
# 语法​​：TTL key
# ​​返回值​​：
# ​​正整数​​：键的剩余生存时间（秒），例如 59 表示 59 秒后过期。
# ​​-1​​：键存在但未设置过期时间（永久有效）。
# ​​-2​​：键不存在或已被删除


# EXPIRE key seconds​​
# 设置秒级过期时间（如 EXPIRE session_id 3600 表示 1 小时后过期）。
# ​​PEXPIRE key milliseconds​​
# 设置毫秒级过期时间（如 PEXPIRE token 5000 表示 5 秒后过期）。
# ​​SET key value EX seconds​​
# 在写入键值时直接设置过期时间（如 SET cache_data "result" EX 60）。


# Redis 通过两种策略删除过期键：

# ​​惰性删除（Lazy Deletion）​​
# 访问键时检查是否过期，过期则立即删除。节省 CPU 但可能导致内存浪费。
# ​​定期删除（Active Expiration）​​
# 默认每秒随机抽查 20 个键（可配置），删除已过期的键，平衡内存与 CPU 开销
# -----------------------------------应用---------------------------------------------------
# ​​缓存管理​​: 为临时数据（如验证码、API 结果）设置 TTL，避免内存耗尽
# ​​会话控制​​: 用户会话（Session）设置 TTL 实现自动登出
# 防缓存穿透​​: 对不存在的键设置短暂 TTL（如 EXPIRE null_key 10），避免重复查询数据库



# 字符串类型： string
# 哈希类型： hash
# 列表类型： list
# 集合类型： set
# 有序集合类型： sortedset（zset）


# String(字符串)
# 字符串类型是Redis最基础的数据结构，其它的几种数据结构都是在字符串类型基础上构建的，
# 字符串的值可以是：字符串、数字、二进制，但其值最大不能超过512M。

# 使用场景： 缓存、计数器、对象存储缓存（共享session）、限速
# 分布式锁， set key value  nx ex ：nx 是否存在， ex 失效时间
# 通关位运算，实现每日签到
# 累加器

# set key value： 设置一个key的value值
# setnx key value： 仅当key不存在时进行set
# setex key seconds value： set 键值对并设置过期时间
# mset key value [key value …]： 设置多个key value
# msetnx key1 value1 [key2 value2…]： 批量设置键值对，仅当参数中所有的key都不存在时执行，原子性操作，一起成功，一起失败
# get key： 返回key的value
# mget key [key …] ： 批量获取多个key保存的值
# exists key [key …]： 查询一个key是否存在
# decr/incr key： 将指定key的value数值进行+1/-1(仅对于数字)
# incrby/decrbyB key n： 按指定的步长对数值进行加减
# incrbyfloat key n： 为数值加上浮点型数值
# append key value： 向指定的key的value后追加字符串
# strlen key： 返回key的string类型value的长度。
# getset key value： 设置一个key的value，并获取设置前的值，如果不存在则返回null
# setrange key offset value： 设置指定位置的字符
# getrange key start end： 获取存储在key上的值的一个子字符串


# List(列表)
# Redis列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素到列表的头部（左边）或者尾部（右边），也可以获取指定范围指定下标的元素等。一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

# 两个特点：
# 1.列表中的元素是有序的，可以通过索引下标获取某个元素霍某个某个范围内的元素列表
# 2.列表中的元素可以是重复的

# 使用场景： 消息队列、栈、文章列表等。 阻塞队列，窗口查询（战绩）

# lpush/rpush key value1[value2…]： 从左边/右边向列表中PUSH值(一个或者多个)
# lpushx/rpushx key value： 向已存在的列名中push值（一个或者多个），list不存在 lpushx失败
# linsert key before|after pivot value： 在指定列表元素的前/后 插入value
# 查找操作
# lindex key index： 通过索引获取列表元素
# lrange key start end： 获取list 起止元素 （索引从左往右 递增）
# llen key： 查看列表长度
# 删除操作
# lpop/rpop key： 从最左边/最右边移除值 并返回
# lrem key count value： count >0：从头部开始搜索 然后删除指定的value 至多删除count个 count < 0：从尾部开始搜索… count = 0：删除列表中所有的指定value。
# ltrim key start end： 通过下标截取指定范围内的列表
# rpoplpush source destination： 将列表的尾部(右)最后一个值弹出，并返回，然后加到另一个列表的头部
# 修改操作
# lset key index value： 通过索引为元素设值
# 阻塞操作
# blpop/brpop key1[key2] timout： 移出并获取列表的第一个/最后一个元素，如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
# brpoplpush source destination timeout： 和rpoplpush功能相同，如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。



# Hash（哈希）
# 几乎所有的编程语言都提供了哈希（hash）结构，Redis中 hash 是一个string类型的field和value的映射表value={{field1,value1},{field2,value2}…}，可以将一个Hash表作为一个对象进行存储，表中存放对象的信息。

# 应用场景： 用户信息缓存
# Redis Hash 的核心价值在于高效地存储和访问具有多个属性的结构化对象。
# 它在需要原子性操作单个字段、节省空间（相比多个 Key）、批量获取部分数据等场景下表现出色。
# 选择 Hash 还是 String（存储序列化 JSON）取决于访问模式：
# 频繁访问/更新部分字段选 Hash，总是访问整个对象且更新少可选 String。


# Zset（有序集合）
# 在有序集合中保留了不能有重复成员的特性，但其中的成员是可以排序的，每一个元素都会关联一个double类型的分数（score）作为排序依据，score相同时按字典顺序排序。redis正是通过分数来为集合中的成员进行从小到大的排序。

# 应用场景： 排行榜系统，成绩单，工资表
# zset 有个分数，这个分数非常有用，例如可以用来分页
#  优先级队列






# ------------------------------------------------------------------
# 实时写入： 当数据变化时，

#     用户 -- 修改数据库 ---  数据库返回结果 ----- 立马更新缓存  

#     用户可以实时看到变化，  
#     如果 设置缓存服务器报错，或多个用户多次写入，可能导致数据不一致脏数据问题


# 异步写入：数据变化时 用另外一个线程写入缓存

#     无法避免上面的脏数据问题，反而会更加激化问题，解决方式时再次查询然后写入缓存，即便这样也不能完全解决脏数据问题


# 用户修改 ----------- 应用服务器  ---------------  修改数据库

#                             ------- 查询刚才修改的数据 ----
#                             ------- 将查询的结果同步到缓存 



# 读取实时写入

#     修改数据后----  返回给用户，---- 同时无效掉缓存
#     这样 用户查询缓存的时候就会触发更新缓存




# 读取时 异步 写入


# --------------------------------------------
# 固定时间失效： 如每天零点失效
# 相对时间失效： 3分钟后失效




# ----------------------------------------
# 缓存不一致 ，-------综合考虑影响  业务是否可以容忍